package com.yonyou.sto.modules.ims.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.support.json.JSONUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.yonyou.sto.common.api.CommonResult;
import com.yonyou.sto.common.domain.OpenBillBuilder;
import com.yonyou.sto.domain.InvoiceStatusEnums;
import com.yonyou.sto.modules.ims.dto.BillDto;
import com.yonyou.sto.modules.ims.dto.CallbackInvoiceData;
import com.yonyou.sto.modules.ims.dto.CallbackInvoiceParam;
import com.yonyou.sto.modules.ims.mapper.ImsBillMapper;
import com.yonyou.sto.modules.ims.model.ImsBill;
import com.yonyou.sto.modules.ims.model.ImsBillItem;
import com.yonyou.sto.modules.ims.model.ImsInvoice;
import com.yonyou.sto.modules.ims.model.ImsInvoiceItem;
import com.yonyou.sto.modules.ims.service.*;
import com.yonyou.sto.modules.ums.util.HttpRestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author aegon
 * @since 2020-10-10
 */
@Service
public class ImsBillServiceImpl extends ServiceImpl<ImsBillMapper, ImsBill> implements ImsBillService {

    private static final Logger LOGGER = LoggerFactory.getLogger(OpenBillServiceImpl.class);

    @Value("${yonyoucloud.app_id}")
    private String APP_ID;

    @Value("${yonyoucloud.domain}")
    private String DOMAIN;

    @Value("${yonyoucloud.cancel_url}")
    private String CANCEL_URL;

    @Value("${yonyoucloud.nc_url}")
    private String NC_URL;
    @Resource
    private ImsBillItemService billItemService;

    @Resource
    private OpenBillBuilder openBillBuilder;

    @Resource
    private PushBillService pushBillService;

    @Resource
    private ImsInvoiceService invoiceService;
    @Resource
    private ImsInvoiceItemService invoiceItemService;
    @Override
    public CommonResult<Map<String, Object>> list(String username, Integer pageSize, Integer pageNum, String billNo, String billCode, String billSerial, String billSn, String sellerName, String buyerName, Integer status, Integer billType, String startTime, String endTime) {

        QueryWrapper<ImsBill> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ImsBill> lambda = wrapper.lambda();

        if (StrUtil.isNotEmpty(billSerial)) lambda.like(ImsBill::getBillSerial, billSerial);

        if (StrUtil.isNotEmpty(billNo)) lambda.like(ImsBill::getBillNo, billNo);

        if (StrUtil.isNotEmpty(billCode)) lambda.like(ImsBill::getBillCode, billCode);

        if (StrUtil.isNotEmpty(billSn)) lambda.like(ImsBill::getBillSn, billSn);

        if (StrUtil.isNotEmpty(sellerName)) lambda.like(ImsBill::getSellerName, sellerName);

        if (StrUtil.isNotEmpty(buyerName)) lambda.like(ImsBill::getBuyerName, buyerName);

        if (status != null) {
            lambda.eq(ImsBill::getStatus, status);
        } else {
            lambda.in(ImsBill::getStatus, 2, 3, 5);
        }

        if (billType != null) lambda.like(ImsBill::getBillType, billType);

        if (StrUtil.isNotBlank(startTime))
            lambda.ge(ImsBill::getCreateTime, DateUtil.parse(startTime, DatePattern.NORM_DATE_FORMAT));

        if (StrUtil.isNotBlank(endTime))
            lambda.le(ImsBill::getCreateTime, DateUtil.parse(endTime, DatePattern.NORM_DATE_FORMAT));

        lambda.orderByDesc(ImsBill::getCreateTime);

        List<ImsBill> bills = list(wrapper);

        if (bills.isEmpty()) return CommonResult.validateFailed("暂无数据");

        List<ImsBill> collect = bills.stream().sorted(Comparator.comparing(ImsBill::getCreateTime).reversed()).skip((pageNum - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
        List<Long> ids = collect.stream().map(ImsBill::getId).collect(Collectors.toList());
        List<ImsBillItem> items = billItemService.listByBillIds(ids);

        List<BillDto> dtos = new ArrayList<>();
        collect.forEach(bill -> {
            BillDto dto = new BillDto();
            BeanUtils.copyProperties(bill, dto);
            dto.setBillItems(items.stream().filter(is -> is.getBillId().equals(dto.getId())).collect(Collectors.toList()));
            dto.setCreateTime(DateUtil.format(bill.getCreateTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));
            dto.setRedTime(DateUtil.format(bill.getRedTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));
            dto.setCancelTime(DateUtil.format(bill.getCancelTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));
            dtos.add(dto);
        });

        Map<String, Object> result = new HashMap<>();
        result.put("list", dtos);
        result.put("pageNum", pageNum);
        result.put("pageSize", pageSize);
        result.put("total", bills.size());

        return CommonResult.success(result);
    }

    @Override
    public CommonResult<Map<String, Object>> listApply(String username, Integer pageSize, Integer pageNum, String billNo, String billCode, String billSerial, String billSn, String sellerName, String buyerName, Integer status, Integer billType, String startTime, String endTime) {

        QueryWrapper<ImsBill> wrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ImsBill> lambda = wrapper.lambda();

        if (StrUtil.isNotEmpty(billSerial)) lambda.like(ImsBill::getBillSerial, billSerial);

        if (StrUtil.isNotEmpty(billNo)) lambda.like(ImsBill::getBillNo, billNo);

        if (StrUtil.isNotEmpty(billCode)) lambda.like(ImsBill::getBillCode, billCode);

        if (StrUtil.isNotEmpty(billSn)) lambda.like(ImsBill::getBillSn, billSn);

        if (StrUtil.isNotEmpty(sellerName)) lambda.like(ImsBill::getSellerName, sellerName);

        if (StrUtil.isNotEmpty(buyerName)) lambda.like(ImsBill::getBuyerName, buyerName);

        if (status != null) {
            lambda.eq(ImsBill::getStatus, status);
        } else {
            lambda.in(ImsBill::getStatus, 2, 3, 5,9);
        }

        if (billType != null) lambda.like(ImsBill::getBillType, billType);

        if (StrUtil.isNotBlank(startTime))
            lambda.ge(ImsBill::getCreateTime, DateUtil.parse(startTime, DatePattern.NORM_DATE_FORMAT));

        if (StrUtil.isNotBlank(endTime))
            lambda.le(ImsBill::getCreateTime, DateUtil.parse(endTime, DatePattern.NORM_DATE_FORMAT));

        lambda.orderByDesc(ImsBill::getCreateTime);

        List<ImsBill> bills = list(wrapper);

        if (bills.isEmpty()) return CommonResult.validateFailed("暂无数据");

        List<ImsBill> collect = bills.stream().sorted(Comparator.comparing(ImsBill::getCreateTime).reversed()).skip((pageNum - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
        List<Long> ids = collect.stream().map(ImsBill::getId).collect(Collectors.toList());
        List<ImsBillItem> items = billItemService.listByBillIds(ids);

        List<BillDto> dtos = new ArrayList<>();
        collect.forEach(bill -> {
            BillDto dto = new BillDto();
            BeanUtils.copyProperties(bill, dto);
            dto.setBillItems(items.stream().filter(is -> is.getBillId().equals(dto.getId())).collect(Collectors.toList()));
            dto.setCreateTime(DateUtil.format(bill.getCreateTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));
            dto.setRedTime(DateUtil.format(bill.getRedTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));
            dto.setCancelTime(DateUtil.format(bill.getCancelTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));
            dtos.add(dto);
        });

        Map<String, Object> result = new HashMap<>();
        result.put("list", dtos);
        result.put("pageNum", pageNum);
        result.put("pageSize", pageSize);
        result.put("total", bills.size());

        return CommonResult.success(result);
    }

    @Override
    public boolean splitAddBill(String billSn, List<Map<String, Object>> result) {

        result.forEach(re -> {
            ImsBill bill = new ImsBill();
            bill.setBillSerial((String) re.get("fpqqlsh"));
            bill.setBillSn(billSn);

            bill.setSellerName((String) re.get("xsfMc"));
            bill.setSellerAddressPhone((String) re.get("xsfDzdh"));
            bill.setSellerBankAccount((String) re.get("xsfYhzh"));
            bill.setSellerTaxSn((String) re.get("xsfNsrsbh"));

            bill.setBuyerBankAccount((String) re.get("gmfYhzh"));
            bill.setBuyerName((String) re.get("gmfMc"));
            bill.setBuyerAddressPhone((String) re.get("gmfDzdh"));
            bill.setBuyerTaxSn((String) re.get("gmfNsrsbh"));

            bill.setPayAmount(BigDecimal.valueOf((Double) re.get("hjje")));
            bill.setTaxAmount(BigDecimal.valueOf((Double) re.get("hjse")));
            bill.setTaxTotal(BigDecimal.valueOf((Double) re.get("jshj")));
            bill.setNote((String) re.get("bz"));
            bill.setBillType(Integer.valueOf(re.get("fplx").toString()));
            bill.setCreateTime(new Date());
            bill.setStatus(InvoiceStatusEnums.IN.getCode());

            baseMapper.insert(bill);
            billItemService.addBillItem(bill.getId(), bill.getBillSerial(), (List<Map<String, Object>>) re.get("items"));
        });

        return true;
    }

    @Override
    public boolean splitAddOpenBill(String billSn, List<Map<String, Object>> result) {

        result.forEach(re -> {
            ImsBill bill = new ImsBill();
            bill.setBillSerial((String) re.get("fpqqlsh"));
            bill.setBillSn(billSn);

            bill.setSellerName((String) re.get("xsfMc"));
            bill.setSellerAddressPhone((String) re.get("xsfDzdh"));
            bill.setSellerBankAccount((String) re.get("xsfYhzh"));
            bill.setSellerTaxSn((String) re.get("xsfNsrsbh"));

            bill.setBuyerBankAccount((String) re.get("gmfYhzh"));
            bill.setBuyerName((String) re.get("gmfMc"));
            bill.setBuyerAddressPhone((String) re.get("gmfDzdh"));
            bill.setBuyerTaxSn((String) re.get("gmfNsrsbh"));

            bill.setPayAmount(BigDecimal.valueOf((Double) re.get("hjje")));
            bill.setTaxAmount(BigDecimal.valueOf((Double) re.get("hjse")));
            bill.setTaxTotal(BigDecimal.valueOf((Double) re.get("jshj")));
            bill.setNote((String) re.get("bz"));
            bill.setBillType(Integer.valueOf(re.get("fplx").toString()));
            bill.setCreateTime(new Date());
            bill.setStatus(InvoiceStatusEnums.IN.getCode());
            ImsInvoice oneByBillSn = invoiceService.getOneByBillSn(billSn);
            bill.setBillContent(oneByBillSn.getBillContent());
            bill.setContractName(oneByBillSn.getContractName());
            bill.setContractSn(oneByBillSn.getContractSn());
//            baseMapper.insert(bill);
            billItemService.addBillItem(bill.getId(), bill.getBillSerial(), (List<Map<String, Object>>) re.get("items"));
        });

        return true;
    }

    @Override
    public String updateBySerial(CallbackInvoiceParam param) {
        QueryWrapper<ImsInvoice> imsInvoiceQueryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<ImsInvoice> invoiceLambdaQueryWrapper = imsInvoiceQueryWrapper.lambda();
        invoiceLambdaQueryWrapper.eq(ImsInvoice::getBillSerial, param.getFpqqlsh());
        ImsInvoice imsInvoice=invoiceService.getOne(invoiceLambdaQueryWrapper);


        if (BeanUtil.isEmpty(imsInvoice)) return "根据流水号未查出发票信息";

        Gson gson = new Gson();
        CallbackInvoiceData data = gson.fromJson(param.getData(), CallbackInvoiceData.class);

        if ("0000".equals(param.getCode())) {

            Map<String, String> params= new HashMap<>();
            params.put("lx", imsInvoice.getDjlx());
            params.put("pk", imsInvoice.getPkNch());
            params.put("fphm", data.getFpHm());
            params.put("fpdm",data.getFpDm());


            try {
                HttpRestUtils.post(NC_URL, JSONUtils.toJSONString(params));
            } catch (Exception e) {

                LOGGER.error( "NC发送失败"+e.getMessage());
            }


            LambdaUpdateWrapper<ImsInvoice> imsInvoiceLambdaUpdateWrapper=new LambdaUpdateWrapper<>();
            imsInvoiceLambdaUpdateWrapper.eq(ImsInvoice::getBillSerial, param.getFpqqlsh())
                    .set(ImsInvoice::getStatus, InvoiceStatusEnums.SUCCESS.getCode())
                    .set(ImsInvoice::getDef1, param.getShareurl())//发票提URL
                    .set(ImsInvoice::getDef2, param.getSharecode())//发票提取码
                    .set(ImsInvoice::getBillNo, data.getFpHm())//
                    .set(ImsInvoice::getBillCode, data.getFpDm());
            invoiceService.update(null,imsInvoiceLambdaUpdateWrapper);
            LambdaUpdateWrapper<ImsInvoiceItem> itemLambdaUpdateWrapper=new LambdaUpdateWrapper<>();
            itemLambdaUpdateWrapper.eq(ImsInvoiceItem::getBillSerial, param.getFpqqlsh())
                    .set(ImsInvoiceItem::getStatus, InvoiceStatusEnums.SUCCESS.getCode() );
            invoiceItemService.update(null,itemLambdaUpdateWrapper);
            return "开票成功";
        } else {
            LambdaUpdateWrapper<ImsInvoice> imsInvoiceLambdaUpdateWrapper=new LambdaUpdateWrapper<>();
            imsInvoiceLambdaUpdateWrapper.eq(ImsInvoice::getBillSerial, param.getFpqqlsh())
                    .set(ImsInvoice::getStatus, InvoiceStatusEnums.FAILED.getCode());
            invoiceService.update(null,imsInvoiceLambdaUpdateWrapper);
            LambdaUpdateWrapper<ImsInvoiceItem> itemLambdaUpdateWrapper=new LambdaUpdateWrapper<>();
            itemLambdaUpdateWrapper.eq(ImsInvoiceItem::getBillSerial, param.getFpqqlsh())
                    .set(ImsInvoiceItem::getStatus, InvoiceStatusEnums.FAILED.getCode() );
            invoiceItemService.update(null,itemLambdaUpdateWrapper);
            return "开票失败";
        }


    }

    @Override
    public CommonResult info(Long id) {
        ImsBill byId = getById(id);
        BillDto dto = new BillDto();
        BeanUtil.copyProperties(byId, dto);
        dto.setCreateTime(DateUtil.format(byId.getCreateTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));
        dto.setRedTime(DateUtil.format(byId.getRedTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));
        dto.setCancelTime(DateUtil.format(byId.getCancelTime(), DatePattern.NORM_DATETIME_MINUTE_PATTERN));

        List<ImsBillItem> items = billItemService.listByBillIds(Collections.singletonList(id));
        dto.setBillItems(items);

        return CommonResult.success(dto);
    }

    @Override
    public CommonResult<String> cancel(List<Long> billIds) {

        List<ImsBill> bills = listByIds(billIds);
        long n0 = bills.stream().filter(b -> b.getStatus() != InvoiceStatusEnums.SUCCESS.getCode()).count();
        if (n0 > 0) return CommonResult.failed("发票未成功开票,不能作废!");

        long n1 = bills.stream().filter(b -> !DateUtil.isSameMonth(b.getCreateTime(), DateUtil.date())).count();
        if (n1 > 0) return CommonResult.failed("跨月发票不能作废!");

        bills.forEach(bill -> {
            Map<String, String> dto = new HashMap<>();
            dto.put("fpDm", bill.getBillCode());
            dto.put("fpHm", bill.getBillNo());

            GsonBuilder builder = new GsonBuilder();
            Map<String, String> paramsMap = new HashMap<>();
            paramsMap.put("requestdatas", builder.create().toJson(dto));

            LOGGER.info("作废接口参数报文:   " + paramsMap);

            Map resultMap = openBillBuilder.callInvoiceApply(DOMAIN + CANCEL_URL + APP_ID, paramsMap);
            LOGGER.info("作废接口返回报文:   " + resultMap);
        });

        List<ImsBill> c0 = bills.stream().peek(bill -> {
            bill.setStatus(InvoiceStatusEnums.CANCEL.getCode());
            bill.setCancelTime(new Date());
        }).collect(Collectors.toList());
        boolean b = updateBatchById(c0);
        // 推悦闻 改原收款单状态
        List<ImsBill> c1 = c0.stream().filter(bill -> bill.getBillSn() != null).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(c1)) {
            pushBillService.pushBillClient1("Cancelled", c1);
            invoiceService.updateStatusBySn(InvoiceStatusEnums.CANCEL.getCode(), c1.stream().map(ImsBill::getBillSn).collect(Collectors.toList()));
        }

        if (b) return CommonResult.success("作废成功");
        return CommonResult.failed("作废失败");
    }

    @Override
    public CommonResult<String> redSpecialBill(List<Long> billIds) {
        List<ImsBill> bills = listByIds(billIds);
//        long n0 = bills.stream().filter(b -> b.getBillType() == 3).count();
//        if (n0 > 0) return CommonResult.failed("增值税普通发票请直接红冲");
//
//        long n1 = bills.stream().filter(b -> DateUtil.isSameMonth(b.getCreateTime(), DateUtil.date())).count();
//        if (n1 > 0) return CommonResult.failed("当月发票不能红冲!");

        List<ImsBill> collect = bills.stream().peek(bill -> {
            bill.setStatus(InvoiceStatusEnums.RED.getCode());
            bill.setRedTime(new Date());
        }).collect(Collectors.toList());

        boolean b = updateBatchById(collect);
        if (b) return CommonResult.success("已修改为红冲状态");
        return CommonResult.failed("操作失败");
    }
}
